#include "sslclientthread.h"

SSLClientThread::SSLClientThread(QObject *parent) : QThread(parent)
{
    hostConnected = false;
    port = 9900;
    serverIP = new QHostAddress();
    runTimer = new QTimer(this);
    connect(runTimer,SIGNAL(timeout()),this,SLOT(_run()));
    moveToThread(this);
}

SSLClientThread::~SSLClientThread()
{
    delete serverIP;
    delete socket;
}

void SSLClientThread::run()
{
    connectToServer();

    runTimer->setInterval(5000);
    runTimer->setSingleShot(true);
    runTimer->start();
    exec();
}

void SSLClientThread::_run()
{
    sendData();
    //QTimer::singleShot(1000,this,SLOT(discontToServer()));
    //runTimer->start();
}

//#define SERVERNAME "winkingzhu.xicp.net"
void SSLClientThread::connectToServer()
{
    if(!hostConnected)
    {
        QString ip;
#ifndef SERVERNAME
        ip.append("localhost");
#else
        ip = QString(SERVERNAME);
#endif

        socket = new QSslSocket(this);
        if(!socket)
            PrintMsg("memory not enough");
#if 1
        /**在设置了ignoreSslErrors(...)后，sslerror 信号还是会被发射的,只是连接不会被drop掉**/
#if 0
        QList<QSslError> expectedSslErrors;
        QList<QSslCertificate> certList = QSslCertificate::fromPath("../certificates/server.crt");
        QSslError error(QSslError::HostNameMismatch,certList.at(0));
        expectedSslErrors.append(error);
        socket->ignoreSslErrors(expectedSslErrors);
#endif
        //GetSslRelateInfo::getCertificateDetail(certList.at(0));

#endif
#if 0   /*查看ca证书数据库*/
        PrintMsg("=====================DEFAULT CA DATA BASE============================");
        QList<QSslCertificate > caCrtList = QSslSocket::defaultCaCertificates();
        for(int i = 0; i < caCrtList.count(); i++)
        {
            GetSslRelateInfo::getCertificateDetail(caCrtList.at(i));
        }
        PrintMsg("=====================DEFAULT CA DATA BASE END============================");
#endif

#if 0  /*设置socket的ca数据库*/
        QList<QSslCertificate> caCertList = QSslCertificate::fromPath("../certificates/cacert.pem");
        socket->setCaCertificates(caCertList);
        caCertList = socket->caCertificates();

        PrintMsg("=====================SOCKET CA DATA BASE============================");
        for(int i = 0; i < caCertList.count(); i++)
        {
            GetSslRelateInfo::getCertificateDetail(caCertList.at(i));
        }
        PrintMsg("=====================SOCKET CA DATA BASE END============================");
#endif

        //socket->setPrivateKey("../certificates/client.pem");
        //socket->setLocalCertificate("../certificates/client.crt");
        //握手成功
        connect(socket,SIGNAL(encrypted()),this,SLOT(handleSocketEncrypted()));
        //状态变化
        connect(socket,SIGNAL(modeChanged(QSslSocket::SslMode)),this,SLOT(handleSslModeChanged(QSslSocket::SslMode)));
        //处理SSL错误
        connect(socket,SIGNAL(sslErrors(QList<QSslError>)),this,SLOT(handleSslErrorList(QList<QSslError>)));
        //SSL错误
        connect(socket,SIGNAL(peerVerifyError(QSslError)),this,SLOT(handlePeerVerifyError(QSslError)));
        //socket连接成功
        connect(socket,SIGNAL(connected()),this,SLOT(handleSocketConnected()));
        //socket断开
        connect(socket,SIGNAL(disconnected()),this,SLOT(handleSocketDisconnected()));
        //socket可读
        connect(socket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
        //打印socket状态
        connect(socket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(handleSockStateChange(QAbstractSocket::SocketState)));
        //处理socket错误
        connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(handleSocketError(QAbstractSocket::SocketError)));

#ifdef SERVERNAME
        //socket->connectToHost(ip,port);
        socket->connectToHostEncrypted(ip,port);
#else
        //socket->connectToHost(*serverIP,port);
        socket->connectToHostEncrypted(ip,port);
#endif

        qDebug()<<"Client socket Mode: "<<socket->mode();
        hostConnected = true;
        qDebug()<<"SSLClientThread::connectToServer";
    }

}

void SSLClientThread::discontToServer()
{
    if(socket)
        socket->disconnectFromHost();
    quit();
}

void SSLClientThread::handleSocketConnected()
{
    int length = 0;
    QString msg = QString("Client:I am connected!");
    if((length = socket->write(msg.toLatin1(),msg.length())) != msg.length())
    {
        return;
    }
}

void SSLClientThread::sendData()
{
    if(!socket->isEncrypted())
        return;
    QString msg = QString("hello I am client");
    socket->write(msg.toLatin1(),msg.length());
}


void SSLClientThread::handleSockStateChange(const QAbstractSocket::SocketState &socketState)
{
    qDebug()<<"SSLClientThread::handleSockStateChange:"<<socketState;
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        PrintMsg("Client:  The socket is not connected");
        break;
    case QAbstractSocket::HostLookupState:
        PrintMsg("Client:  The socket is performing a host name lookup");
        break;
    case QAbstractSocket::ConnectingState:
        PrintMsg("Client:  The socket has started establishing a connection");
        break;
    case QAbstractSocket::BoundState:
        PrintMsg("Client:  The socket is bound to an address and port (for servers).");
        break;
    case QAbstractSocket::ClosingState:
        PrintMsg("Client:  The socket is about to close (data may still be waiting to be written).");
        break;
    case QAbstractSocket::ListeningState:
        PrintMsg("Client:  ListeningState .For internal use only.");
        break;
    default:
        PrintMsg("Client:  Not match any states.");
        break;
    }
    PrintMsg("===========================");
}

void SSLClientThread::handleSocketEncrypted()
{
    qDebug()<<"SSLClientThread::handleSocketEncrypted.";
}

void SSLClientThread::handleSslModeChanged(QSslSocket::SslMode mode)
{
    switch(mode)
    {
    case QSslSocket::UnencryptedMode:
        qDebug()<<"SSLClientThread::handleSslModeChanged:"<<"UnencryptedMode";
        break;
    case QSslSocket::SslClientMode:
        qDebug()<<"SSLClientThread::handleSslModeChanged:"<<"SslClientMode";
        break;
    case QSslSocket::SslServerMode:
        qDebug()<<"SSLClientThread::handleSslModeChanged:"<<"SslServerMode";
        break;
    }
}

void SSLClientThread::handleSslErrorList(const QList<QSslError> &errorList)
{
    qDebug()<<"SSLClientThread::handleSslErrorList:"<<errorList.count();
    for(int i = 0 ;i < errorList.count(); i++)
    {
        QSslError SslError = errorList.at(i);
        handleSslError(SslError);
    }
}

void SSLClientThread::handlePeerVerifyError(const QSslError &error)
{
#if 1
    handleSslError(error);
#endif
}

void SSLClientThread::handleSslError(const QSslError &error)
{    
    QSslError::SslError sslerror=error.error();
    qDebug()<<"SSLClientThread::handleSslError:"<<(int)sslerror<<" "<<error.errorString();
    QSslCertificate cer = error.certificate();

    if(cer.isNull())
    {
        qDebug()<<"Cer is Null";
    }
    else
    {        
//        GetSslRelateInfo::getCertificateDetail(cer);
//        if(cer.isValid())
//        {
//            PrintMsg("Certificates is Valid.");
//        }
//        else
//        {
//            PrintMsg("Certificates is Not Valid.");
//        }
    }

    switch(error.error())
    {
    case QSslError::NoError:
        break;
    case QSslError::UnableToGetIssuerCertificate:
        break;
    case QSslError::UnableToDecryptCertificateSignature:
        break;
    case QSslError::UnableToDecodeIssuerPublicKey:
        break;
    case QSslError::CertificateSignatureFailed:
        break;
    case QSslError::CertificateNotYetValid:
        break;
    case QSslError::CertificateExpired:
        break;
    case QSslError::InvalidNotBeforeField:
        break;
    case QSslError::InvalidNotAfterField:
        break;
    case QSslError::SelfSignedCertificate:
        socket->ignoreSslErrors();
        break;
    case QSslError::SelfSignedCertificateInChain:
        break;
    case QSslError::UnableToGetLocalIssuerCertificate:
        break;
    case QSslError::UnableToVerifyFirstCertificate:
        break;
    case QSslError::CertificateRevoked:
        break;
    case QSslError::InvalidCaCertificate:
        break;
    case QSslError::PathLengthExceeded:
        break;
    case QSslError::InvalidPurpose:
        break;
    case QSslError::CertificateUntrusted:
        break;
    case QSslError::CertificateRejected:
        break;
    case QSslError::SubjectIssuerMismatch:
        break;
    case QSslError::AuthorityIssuerSerialNumberMismatch:
        break;
    case QSslError::NoPeerCertificate:
        break;
    case QSslError::HostNameMismatch:
        if(cer.subjectInfo(QSslCertificate::CommonName).contains("GameServer"))
        {
            //socket->ignoreSslErrors();
        }
        //socket->ignoreSslErrors();
        break;
    case QSslError::UnspecifiedError:
        break;
    case QSslError::NoSslSupport:
        break;
    default:
        qDebug()<<"no match any ssl error.";
        break;
    }    
}

void SSLClientThread::handleSocketError(const QAbstractSocket::SocketError &socketError)
{
    qDebug()<<"SSLClientThread::handleSocketError:"<<socketError;
    switch(socketError)
    {
    case QAbstractSocket::ConnectionRefusedError:
        PrintMsg("The connection was refused by the peer (or timed out).");
        break;
    case QAbstractSocket::RemoteHostClosedError:
        PrintMsg("The remote host closed the connection. Note that the client socket (i.e., this socket) will be closed after the remote close notification has been sent.");
        break;
    case QAbstractSocket::HostNotFoundError:
        PrintMsg("The host address was not found.");
        break;
    case QAbstractSocket::SocketAccessError:
        PrintMsg("The socket operation failed because the application lacked the required privileges.");
        break;
    case QAbstractSocket::SocketResourceError:
        PrintMsg("The local system ran out of resources (e.g., too many sockets).");
        break;
    case QAbstractSocket::SocketTimeoutError:
        PrintMsg("The socket operation timed out.");
        break;
    case QAbstractSocket::DatagramTooLargeError:
        PrintMsg("The datagram was larger than the operating system's limit (which can be as low as 8192 bytes).");
        break;
    case QAbstractSocket::NetworkError:
        PrintMsg("An error occurred with the network (e.g., the network cable was accidentally plugged out).");
        break;
    case QAbstractSocket::AddressInUseError:
        PrintMsg("The address specified to bind() is already in use and was set to be exclusive.");
        break;
    case QAbstractSocket::SocketAddressNotAvailableError:
        PrintMsg("The address specified to bind() does not belong to the host.");
        break;
    case QAbstractSocket::UnsupportedSocketOperationError:
        PrintMsg("The requested socket operation is not supported by the local operating system (e.g., lack of IPv6 support).");
        break;
    case QAbstractSocket::ProxyAuthenticationRequiredError:
        PrintMsg("The socket is using a proxy, and the proxy requires authentication.");
        break;
    case QAbstractSocket::SslHandshakeFailedError:
        PrintMsg("The SSL/TLS handshake failed, so the connection was closed (only used in SslSocket)");
        break;
    case QAbstractSocket::UnfinishedSocketOperationError:
        PrintMsg("Used by AbstractSocketEngine only, The last operation attempted has not finished yet (still in progress in the background).");
        break;
    case QAbstractSocket::ProxyConnectionRefusedError:
        PrintMsg("Could not contact the proxy server because the connection to that server was denied");
        break;
    case QAbstractSocket::ProxyConnectionClosedError:
        PrintMsg("The connection to the proxy server was closed unexpectedly (before the connection to the final peer was established)");
        break;
    case QAbstractSocket::ProxyConnectionTimeoutError:
        PrintMsg("The connection to the proxy server timed out or the proxy server stopped responding in the authentication phase.");
        break;
    case QAbstractSocket::ProxyNotFoundError:
        PrintMsg("The proxy address set with setProxy() (or the application proxy) was not found.");
        break;
    case QAbstractSocket::ProxyProtocolError:
        PrintMsg("The connection negotiation with the proxy server because the response from the proxy server could not be understood.");
        break;
    case QAbstractSocket::UnknownSocketError:
        PrintMsg("An unidentified error occurred.");
        break;
    default:
        PrintMsg("Not match any errors.");
        break;
    }
}


void SSLClientThread::handleSocketDisconnected()
{
    qDebug()<<"SSLClientThread::handleSocketDisconnected";
}

void SSLClientThread::dataReceived()
{
    while(socket->bytesAvailable() > 0 )
    {
        QByteArray datagram;
        datagram.resize(socket->bytesAvailable());
        socket->read(datagram.data(),datagram.size());
        qDebug() << datagram;
    }
}
